package com.iretailer.report.analyze.netty;

import com.alibaba.fastjson.JSON;
import com.iretailer.report.analyze.annotation.AnalyzeClass;
import com.iretailer.report.analyze.commonUtil.Analyze;
import com.iretailer.report.init.annotation.BootLoading;
import com.iretailer.report.init.annotation.ExecutionMethod;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Auther: xjw
 * @Date: 2018/12/4 17:52
 * @Description:
 */
@BootLoading
@Component
public class NettyHttpServer {
    private static Logger log = LoggerFactory.getLogger(NettyHttpServer.class);
    @Value("${netty.port}")
    private Integer port;
    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private ExecutorService threadPool;

    public static Map<String, Analyze> pathMap = new HashMap<>();

    @Value("${enableNetty:true}")
    private boolean enableNetty;

    @ExecutionMethod
    public void start() {
        if (enableNetty) {
            threadPool.execute(() -> {
                AtomicInteger connectNum = new AtomicInteger(0);
                //首先 执行
                getAllPath();
                log.info("All path {}", JSON.toJSONString(pathMap.keySet()));
                EventLoopGroup bossGroup = new NioEventLoopGroup(1);
                EventLoopGroup workerGroup = new NioEventLoopGroup();
                try {
                    ServerBootstrap b = new ServerBootstrap();
                    b.group(bossGroup, workerGroup)
                            .channel(NioServerSocketChannel.class)
                            .childHandler(new NettyServerHandlerInit(connectNum))
                            .option(ChannelOption.SO_BACKLOG, 1024 * 1024)
                            .childOption(ChannelOption.SO_KEEPALIVE, true); //清除死连接，维持活跃的
                    // 绑定端口，开始接收进来的连接
                    ChannelFuture f = b.bind(port).sync();
                    log.info("-----netty start [{}] ------", port);
                    // 等待服务器 socket 关闭 。在这个例子中，这不会发生，但你可以优雅地关闭你的服务器。
                    f.channel().closeFuture().sync();
                } catch (Exception e) {
                    log.error("----- NettySever start fail", e);
                } finally {
                    //优雅的停机
                    workerGroup.shutdownGracefully();
                    bossGroup.shutdownGracefully();
                }
            });
        }
    }

    private void getAllPath() {
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(AnalyzeClass.class);
        beansWithAnnotation.entrySet().forEach(it -> {
            Analyze analyze = (Analyze) applicationContext.getBean(it.getValue().getClass());
            String[] paths = analyze.analyzePath();
            for (String p : paths) {
                pathMap.put(p, analyze);
            }
        });
    }

}
